package com.sec.etech.file.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.aspose.cells.PdfSaveOptions;
import com.aspose.words.SaveFormat;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import com.sec.etech.file.dto.PositionDto;
import com.sec.etech.file.dto.SignatureDto;
import com.sec.etech.file.mapper.EtechFileLogMapper;
import com.sec.etech.file.mapper.EtechFileMapper;
import com.sec.etech.file.mapper.EtechFileTempMapper;
import com.sec.etech.file.model.EtechFile;
import com.sec.etech.file.model.EtechFileLog;
import com.sec.etech.file.model.EtechFileTemp;
import com.sec.etech.file.util.ImageConvert;
import com.sec.etech.file.vo.EtechFileVersionVo;
import com.sec.etech.org.service.EtechUserUtil;
import com.sec.etech.sys.util.DbUtil;
import com.sec.etech.sys.util.RequestHolder;
import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.core.ZipFile;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.openbpm.base.api.exception.BusinessMessage;
import org.openbpm.base.api.response.impl.ResultMsg;
import org.openbpm.base.core.id.IdUtil;
import org.openbpm.base.core.util.StringUtil;
import org.openbpm.base.core.util.ZipUtil;
import org.openbpm.base.manager.impl.BaseManager;
import org.openbpm.base.rest.util.RequestUtil;
import org.openbpm.org.api.model.IUser;
import org.openbpm.org.api.service.UserService;
import org.openbpm.sys.core.model.SysFile;
import org.openbpm.sys.upload.IUploader;
import org.openbpm.sys.upload.UploaderFactory;
import org.openbpm.sys.util.ContextUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Etech 文件服务
 */
@Slf4j
@Service("etechFileService")
public class EtechFileService extends BaseManager<String, EtechFile> {

    final Logger LOGGER = LoggerFactory.getLogger(EtechFileService.class);

    @Resource
    private EtechFileMapper etechFileMapper;
    @Resource
    private EtechFileTempMapper etechFileTempMapper;
    @Resource
    private EtechFileLogMapper fileLogMapper;
    //@Resource
    //private EtechFileJob eltechFileJob;
    //@Resource
    //private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    //@Resource
    //private EtechFileTaskService etechFileTaskService;
    @Resource
    UserService userService;
    // 文件根目录
    @Value("${etech.file.base-dir:/app/data2/files/}")
    private String fileHomeDir;
    // 模板文件目录
    @Value("${etech.file.template-dir:/app/data2/files/templates/}")
    private String fileTemplateDir;
    // 工作文件目录/上传文件目录
    @Value("${etech.file.upload-dir:/app/data2/files/uploads/}")
    private String fileUploadDir;
    // 预览文件目录
    @Value("${etech.file.preview-dir:/app/data2/files/previews/}")
    private String filePreviewDir;
    // 临时文件目录
    @Value("${etech.file.temp-dir:/app/data2/files/temp/}")
    private String fileTempDir;
    @Value("${etech.file.online-preview-host:/fileview/}")
    private String onlinePreviewPort;
    @Value("${etech.file.static-dir:/app/data2/files/static/}")
    String staticPath;
    @Value("${etech.file.url-encryption-password:etech}")
    private String urlEncryptionPassword;
    @Resource
    EtechFileHandlerService etechFileHandlerService;
    @Resource
    private EtechFileModulePowerService etechFileModulePowerService;
    //@Resource
    //DocMapper docMapper;

    /**
     * 获取文件home根目录
     *
     * @return
     */
    protected String getFileHome() {
        String path = fileHomeDir;
        if (!FileUtil.isDirectory(path)) {
            path = FileUtil.getTmpDirPath();
        }
        if (!fileHomeDir.endsWith("/")) {
            path = path + File.separator;
        }
        return path;
    }

    public int save(EtechFile etechFile){
       return etechFileMapper.updateById(etechFile);
    }

    /**
     * 获取模板文件根目录
     *
     * @return
     */
    public String getTempleteDir() {
        String path = fileTemplateDir;
        if (StringUtil.isEmpty(path)) {
            path = getFileHome() + "templates" + File.separator;
        }
        if (FileUtil.isDirectory(path)) {
            // 已配置模板文件夹 templates
        } else {
            FileUtil.mkdir(path);
            // like resources/templates/plan/list/xxx
            //path = this.getClass().getClassLoader().getResource("templates/").getPath();
        }
        return path;
    }

    /**
     * 获取模板文件完整路径
     *
     * @param path
     * @return
     */
    public String getTempleteFilePath(String path) {
        String homePath = getTempleteDir();
        return homePath + path;
    }

    /**
     * 获取临时文件根目录
     *
     * @return
     */
    public String getFileTempDir() {
        String path = fileTempDir;
        if (StringUtil.isEmpty(path)) {
            path = getFileHome() + "temp" + File.separator;
        }
        if (!FileUtil.exist(path)) {
            try {
                FileUtil.mkdir(path);
            } catch (Exception e) {
                path = FileUtil.getTmpDirPath();
            }
        }
        return path;
    }

    public String getFileUploadDir(String module) {
        String path = "";
        if (StringUtil.isNotEmpty(module) && (!"document".equals(module))) {
            path = this.getFileHome();
        } else {
            path = this.fileUploadDir;
            if (StringUtil.isEmpty(path)) {
                path = this.getFileHome() + "uploads" + File.separator;
            }
        }
        return path;
    }

    public String getFilePreviewDir() {
        String path = this.filePreviewDir;
        if (StringUtil.isEmpty(path)) {
            path = this.getFileHome() + "previews" + File.separator;
        }
        if (!FileUtil.exist(path)) {
            FileUtil.mkdir(path);
        }
        return path;

    }

    public String getOnlinePreviewHost() {
        String path = this.onlinePreviewPort;
        if (!path.endsWith("/")) {
            path = path + "/";
        }
        return path;

    }

    public void delete(String... fileId) {
        if (ArrayUtil.isEmpty(fileId)) return;
        for (String id : fileId) {
            this.delete(id, true);
        }
    }

    public String uploadFile(InputStream is, String fileName, String module, String uniqueIdentifier) throws Exception {
        EtechFile sysFile = this.upload(is, fileName, null, module, uniqueIdentifier);
        if (sysFile != null) {
            return sysFile.getId();
        } else {
            return null;
        }
    }

    public String uploadFile(InputStream is, String fileName) throws Exception {
        return this.uploadFile(is, fileName, null, null);
    }
    //pdf、tif无水印预览使用
    public InputStream previewByteForPdf(String fileId) throws Exception {
        EtechFile etechFile = this.getFile(fileId);
        if (etechFile == null) {
            throw new BusinessMessage("文件不存在或者已删除！");
        }
        String previewPath = "";
        if (etechFile.isWebUploader()) {
            previewPath = etechFileHandlerService.getDownloadPreviewPath(etechFile);
        } else {
            previewPath = etechFile.getPreviewPath();
            if (StringUtil.isEmpty(previewPath) && (etechFile.getPath().endsWith(".pdf")
                    || etechFile.getPath().endsWith(".tif") || etechFile.getPath().endsWith(".tiff") || etechFile.getPath().endsWith(".TIF"))) {
                previewPath = etechFile.getPath();
            }
        }
        log.info("DOC previewByteForPdf {} {}", fileId, previewPath);
        IUploader uploader = UploaderFactory.getUploader(etechFile.getUploader());
        return uploader.take(previewPath);
    }
    public InputStream previewByte(String fileId) throws Exception {
        EtechFile etechFile = this.getFile(fileId);
        if (etechFile == null) {
            throw new BusinessMessage("文件不存在或者已删除！");
        }
        String previewPath = "";
        if (etechFile.isWebUploader()) {
            previewPath = etechFileHandlerService.getDownloadPreviewPath(etechFile);
        } else {
            previewPath = getAbsPreviewPath(etechFile, null, false);
        }
        IUploader uploader = UploaderFactory.getUploader(etechFile.getUploader());
        return uploader.take(previewPath);
    }

    public InputStream previewByte(Boolean withWatermaker, String fileId) throws Exception {
        EtechFile etechFile = this.getFile(fileId);
        if (etechFile == null) {//查询不到查询临时表
            etechFile = new EtechFile();
            EtechFileTemp etechFileTemp = etechFileTempMapper.selectById(fileId);
            BeanUtil.copyProperties(etechFileTemp, etechFile);
        }
        String substring = "";
        if (StrUtil.isNotBlank(etechFile.getPreviewPath())) {
            substring = FileUtil.getSuffix(etechFile.getPreviewPath());
        } else {
            substring = FileUtil.getSuffix(etechFile.getName());
        }
        String newPath = etechFileHandlerService.getEtechFileTempDir() + StrUtil.format(DateUtil.format(new Date(), "yyyy/MM/dd/{}_{}_HH.{}"), etechFile.getId(), ContextUtil.getCurrentUserAccount(), substring);
        String temppicPath =etechFileHandlerService.getEtechFileTempDir() + StrUtil.format(DateUtil.format(new Date(), "yyyy/MM/dd/{}_{}_HH.{}"), etechFile.getId(), ContextUtil.getCurrentUserAccount()+"temp", "jpg");
        log.info("DOC previewByte {} {}", fileId, newPath);
        try {
            File file = new File(newPath);
            File tempFile=new File(temppicPath);
            if (FileUtil.exist(tempFile) && FileUtil.getSuffix(file.getName()).equals("tif")){
                throw new RuntimeException("<b id=\"color\" style=\"color:red;\">文件正在处理，请稍等后再点击进行下载</b>");
            }
        }catch (RuntimeException e){
            throw e;
        }
        catch (Exception e) {
            throw new BusinessMessage("文件不存在或者已删除！");
        }
        if (etechFile == null) {
            throw new BusinessMessage("文件不存在或者已删除！");
        }
        IUploader uploader = UploaderFactory.getUploader(etechFile.getUploader());
        return uploader.take(newPath);
    }

    public void download(InputStream fis, String fileName, HttpServletResponse response) throws IOException {
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        //设置跨域请求把下面的Content-Disposition暴露给客户端，否则跨域请求(开发npm run dev启动的方式)获取不到Content-Disposition中的文件名会报错
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        ServletOutputStream servletOutputStream = response.getOutputStream();
        IOUtils.copy(fis, servletOutputStream);
        servletOutputStream.flush();
        IoUtil.close(fis);
        IoUtil.close(servletOutputStream);
    }


    public String addWaterMark(String fileId, String user, boolean withUserWatermark, String watermarkText) throws Exception {

        EtechFile etechFile = this.getFile(fileId);
        // 检查预览权限
        if (!checkFilePreviewRight(etechFile, user)) {
            throw new BusinessMessage("无预览权限");
        }

        String previewPath = getAbsPreviewPathWithWatermark(etechFile, user, withUserWatermark, watermarkText);
        if (StringUtil.isNotEmpty(user)) {
            // file log
            this.logFilePreview(etechFile, "preview " + (withUserWatermark ? " with watermark" : ""), ContextUtil.getCurrentUserId());
        }
        FileUtil.copy(previewPath, getFileTempDir() + etechFile.getName(), true);

        return etechFile.getName();
    }

    public String addWaterMarkForBlueprint(String fileId, String user, boolean withUserWatermark, String watermarkText) throws Exception {

        EtechFile etechFile = this.getFile(fileId);
        // 检查预览权限
//        if (!checkFilePreviewRight(etechFile, user)) {
//            throw new BusinessMessage("无预览权限");
//        }

        String previewPath = getAbsPreviewPathWithWatermark(etechFile, user, withUserWatermark, watermarkText);
        if (StringUtil.isNotEmpty(user)) {
            // file log
            this.logFilePreview(etechFile, "preview " + (withUserWatermark ? " with watermark" : ""), ContextUtil.getCurrentUserId());
        }
        FileUtil.copy(previewPath, getFileTempDir() + "wm-" + etechFile.getName(), true);

        return getFileTempDir() + "wm-" + etechFile.getName();
    }

    public String addWaterMarkForBlueprint(String fileId, String user, boolean withUserWatermark, String watermarkText, int i) throws Exception {

        EtechFile etechFile = this.getFile(fileId);
        // 检查预览权限
//        if (!checkFilePreviewRight(etechFile, user)) {
//            throw new BusinessMessage("无预览权限");
//        }

        String previewPath = getAbsPreviewPathWithWatermark(etechFile, user, withUserWatermark, watermarkText);
        if (StringUtil.isNotEmpty(user)) {
            // file log
            this.logFilePreview(etechFile, "preview " + (withUserWatermark ? " with watermark" : ""), ContextUtil.getCurrentUserId());
        }
        FileUtil.copy(previewPath, getFileTempDir() + i + "-wm-" + etechFile.getName(), true);

        return getFileTempDir() + i + "-wm-" + etechFile.getName();
    }


    public void preview(HttpServletResponse response, String fileId, String user, boolean withUserWatermark, String watermarkText) throws Exception {

        EtechFile etechFile = this.getFile(fileId);
        // 检查预览权限
        if (!checkFilePreviewRight(etechFile, user)) {
            throw new BusinessMessage("无预览权限");
        }


        String previewPath = getAbsPreviewPathWithWatermark2(etechFile, user, withUserWatermark, watermarkText);
        if (StringUtil.isNotEmpty(user)) {
            // file log
            this.logFilePreview(etechFile, "preview " + (withUserWatermark ? " with watermark" : ""), ContextUtil.getCurrentUserId());
        }

        if (previewPath == null) {
            return;
        }

        FileInputStream fis = null;
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            if (previewPath.toLowerCase().endsWith(".pdf")) {
                response.setContentType(MediaType.APPLICATION_PDF_VALUE);
                os = response.getOutputStream();
                fis = new FileInputStream(new File(previewPath));
                IOUtils.copy(fis, os);
            } else if (previewPath.toLowerCase().toLowerCase().endsWith(".tif")
                    || previewPath.toLowerCase().toLowerCase().endsWith(".tiff")) {
                response.setContentType(MediaType.IMAGE_JPEG_VALUE);
                os = response.getOutputStream();
                ImageConvert.compressPic(previewPath, os);
            } else {
                response.setHeader("content-type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 文件预览
     *
     * @param response
     * @param fileId
     * @param withUserWatermark 是否带用户水印
     */
    public void preview(HttpServletResponse response, String fileId, String user, boolean withUserWatermark) throws Exception {
        preview(response, fileId, user, withUserWatermark, null);
    }

    /**
     * 临时文件预览
     *
     * @param response
     * @param path
     * @param withUserWatermark 是否带用户水印
     * @param download          是否下载
     * @param downloadPreview   是否下载预览文件
     */
    public void previewTemp(HttpServletResponse response, String path, String user, boolean withUserWatermark, boolean download, boolean downloadPreview) throws Exception {
        String tempDir = getFileTempDir();
        String filePath = tempDir + URLDecoder.decode(path, "utf-8");
        if (!FileUtil.exist(filePath)) {
            throw new BusinessMessage("文件不存在");
        }
        if (download && !downloadPreview) { //如果是下载原文件直接下文件
            download(FileUtil.getInputStream(filePath), FileUtil.getName(URLDecoder.decode(path, "utf-8")), response);
            return;
        }

        String previewPath = getAbsPreviewTempPath(filePath, user, withUserWatermark);
        if (previewPath == null) {
            throw new BusinessMessage("生成预览文件失败");
        }
        if (download && downloadPreview) { //如果是下载预览文件
            download(FileUtil.getInputStream(previewPath), FileUtil.getName(previewPath), response);
            return;
        }
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            if (previewPath.toLowerCase().endsWith(".pdf")) {
                response.setContentType(MediaType.APPLICATION_PDF_VALUE);
                os = response.getOutputStream();
                fis = new FileInputStream(new File(previewPath));
                IOUtils.copy(fis, os);
            } else if (previewPath.toLowerCase().toLowerCase().endsWith(".tif")
                    || previewPath.toLowerCase().toLowerCase().endsWith(".tiff")) {
                response.setContentType(MediaType.IMAGE_JPEG_VALUE);
                os = response.getOutputStream();
                ImageConvert.compressPic(previewPath, os);
            } else {
                response.setHeader("content-type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 模板文件预览
     *
     * @param response
     * @param path
     */
    public void previewTemplate(HttpServletResponse response, String path) throws Exception {
        String templateDir = getTempleteDir();
        String filePath = templateDir + path;
        if (!FileUtil.exist(filePath)) {
            throw new BusinessMessage("文件不存在");
        }
        String fileName = FileUtil.getName(path);
        String previewPath = makePreviewTemplateWithPath(filePath, fileName);
        if (previewPath == null) {
            throw new BusinessMessage("生成预览文件失败");
        }
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            if (previewPath.toLowerCase().endsWith(".pdf")) {
                response.setContentType(MediaType.APPLICATION_PDF_VALUE);
                os = response.getOutputStream();
                fis = new FileInputStream(new File(previewPath));
                IOUtils.copy(fis, os);
            } else if (previewPath.toLowerCase().toLowerCase().endsWith(".tif")
                    || previewPath.toLowerCase().toLowerCase().endsWith(".tiff")) {
                response.setContentType(MediaType.IMAGE_JPEG_VALUE);
                os = response.getOutputStream();
                ImageConvert.compressPic(previewPath, os);
            } else {
                response.setHeader("content-type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    protected boolean checkFilePreviewRight(EtechFile etechFile, String user) {
        // 调用系统权限判断
        //return etechFile.havePreviewRights();
        return etechFileModulePowerService.haveSinglePreviewRights(etechFile);
    }

    public String getAbsPreviewPath(String fileId, String user, boolean withUserWatermark) throws Exception {
        EtechFile etechFile = this.getFile(fileId);
        return getAbsPreviewPath(etechFile, user, withUserWatermark);
    }


    public String getAbsPreviewPathWithWatermark(EtechFile etechFile, String user, boolean withUserWatermark, String markwaterText) throws Exception {

        log.warn("QS !! {} {}", etechFile.getName(), markwaterText);

        // 通用预览文件
        String previewPath = etechFile.getPreviewPath();
        if (StringUtil.isEmpty(previewPath) || !FileUtil.exist(this.getFilePreviewDir() + previewPath)) {
            previewPath = makePreviewWithPath(etechFile, etechFile.getModule());
        }
        // 用户水印预览文件 PDF only
        String userWatermark = null;
        if (withUserWatermark) {
            userWatermark = markwaterText;
        }
        // 用户水印预览文件 PDF only
        if (StringUtil.isNotEmpty(userWatermark) &&
                ((StringUtil.isNotEmpty(previewPath) && previewPath.endsWith(".pdf")) || etechFile.getPath().endsWith(".pdf"))
        ) {
            String srcPreviewPath = null;
            if (StringUtil.isNotEmpty(previewPath)) {
                srcPreviewPath = this.getFilePreviewDir() + previewPath;
            } else {
                srcPreviewPath = this.getFileUploadDir(etechFile.getModule()) + etechFile.getPath();
                previewPath = srcPreviewPath.substring(getFileUploadDir(etechFile.getModule()).length());
            }
            int index = previewPath.lastIndexOf(".");
            String userPreviewPath = previewPath.substring(0, index) + user + previewPath.substring(index);
            pdfAddTextStamp(srcPreviewPath, this.getFilePreviewDir() + userPreviewPath, userWatermark, "lines");
            previewPath = userPreviewPath;
        }

        if (StringUtil.isEmpty(previewPath)) {
            previewPath = this.getFileUploadDir(etechFile.getModule()) + etechFile.getPath();
        }
        if (previewPath != null && !previewPath.startsWith("/")) {
            previewPath = this.getFilePreviewDir() + previewPath;
        }
        return previewPath;
    }

    public String getAbsPreviewPathWithWatermark2(EtechFile etechFile, String user, boolean withUserWatermark, String markwaterText) throws Exception {

        log.warn("QS !! {} {}", etechFile.getName(), markwaterText);

        // 通用预览文件
        String previewPath = etechFile.getPreviewPath();
        if (StringUtil.isEmpty(previewPath) || !FileUtil.exist(this.getFilePreviewDir() + previewPath)) {
            previewPath = makePreviewWithPath(etechFile, etechFile.getModule());
        }
        // 用户水印预览文件 PDF only
        String userWatermark = null;
        if (withUserWatermark) {
            if (StrUtil.isBlank(markwaterText)) {
                userWatermark = markwaterText;//userWatermark = "工号：" + user + " 日期：" + DateUtil.formatDate(new Date());
            } else {
                userWatermark = markwaterText;
            }
        }
        // 用户水印预览文件 PDF only
        if (StringUtil.isNotEmpty(userWatermark) &&
                ((StringUtil.isNotEmpty(previewPath) && previewPath.endsWith(".pdf")) || etechFile.getPath().endsWith(".pdf"))
        ) {
            String srcPreviewPath = null;
            if (StringUtil.isNotEmpty(previewPath)) {
                srcPreviewPath = this.getFilePreviewDir() + previewPath;
            } else {
                srcPreviewPath = this.getFileUploadDir(etechFile.getModule()) + etechFile.getPath();
                previewPath = srcPreviewPath.substring(getFileUploadDir(etechFile.getModule()).length());
            }
            int index = previewPath.lastIndexOf(".");
            String userPreviewPath = previewPath.substring(0, index) + user + previewPath.substring(index);
            pdfAddTextStamp(srcPreviewPath, this.getFilePreviewDir() + userPreviewPath, userWatermark, "lines2");
            previewPath = userPreviewPath;
        }

        if (StringUtil.isEmpty(previewPath)) {
            previewPath = this.getFileUploadDir(etechFile.getModule()) + etechFile.getPath();
        }
        if (previewPath != null && !previewPath.startsWith("/")) {
            previewPath = this.getFilePreviewDir() + previewPath;
        }
        return previewPath;
    }

    protected String getAbsPreviewPath(EtechFile etechFile, String user, boolean withUserWatermark) throws Exception {
        return getAbsPreviewPathWithWatermark(etechFile, user, withUserWatermark, "");
    }

    /**
     * 临时文件预览
     */
    protected String getAbsPreviewTempPath(String filePath, String user, boolean withUserWatermark) throws Exception {
        // 通用预览文件
        String previewPath = makePreviewTempWithPath(filePath, FileUtil.getName(filePath), null);
        // 用户水印预览文件 PDF only
        String userWatermark = null;
        if (withUserWatermark) {
            userWatermark = "工号：" + user + " 日期：" + DateUtil.formatDate(new Date());
        }
        // 用户水印预览文件 PDF only
        if (StringUtil.isNotEmpty(userWatermark) && StringUtil.isNotEmpty(previewPath) && previewPath.toLowerCase().endsWith(".pdf")) {
            String userPreviewPath = previewPath + user + ".pdf";
            pdfAddTextStamp(previewPath, userPreviewPath, userWatermark, "user");
            previewPath = userPreviewPath;
        }
        return previewPath;
    }

    /**
     * 生成带水印预览文件
     *
     * @param fileId
     * @param fileWatermark
     */
    public String makePreviewWithWatermark(String fileId, String fileWatermark) throws Exception {
        EtechFile etechFile = this.getFile(fileId);
        return makePreviewWithPath(etechFile, fileWatermark);
    }


    protected String makePreviewWithPath(EtechFile etechFile, String fileWatermark) throws Exception {
        log.debug("start makePreviewWithPath, path=" + etechFile.getPath());
        String previewPath = etechFile.getPreviewPath();
        String fileName = etechFile.getName();
        /*if (fileName.endsWith(".pdf") || fileName.endsWith(".tif") || fileName.endsWith(".tiff")) {
            if(StringUtil.isEmpty(previewPath)) {
                previewPath = etechFile.getPath();
            }
            if (StringUtil.isNotEmpty(fileWatermark)) {
                FileUtil.copy(getFileUploadDir(etechFile.getModule()) + etechFile.getPath(), getFilePreviewDir() + previewPath, true);
                pdfAddTextStamp(getFilePreviewDir() + previewPath, getFilePreviewDir() + previewPath, fileWatermark, "file");
            }
        }*/
        if (fileName.endsWith(".pdf")) {
            previewPath = etechFile.getPath();
            FileUtil.copy(getFileUploadDir(etechFile.getModule()) + etechFile.getPath(), getFilePreviewDir() + previewPath, true);
            if (StringUtil.isNotEmpty(fileWatermark)) {
                pdfAddTextStamp(getFilePreviewDir() + previewPath, getFilePreviewDir() + previewPath, fileWatermark, "file");
            }
        } else if (fileName.endsWith(".doc") || fileName.endsWith(".docx")) {
            // word2pdf
            previewPath = etechFile.getPath().replace(".docx", ".pdf").replace(".doc", ".pdf");
            word2pdf(getFileUploadDir(etechFile.getModule()) + etechFile.getPath(), getFilePreviewDir() + previewPath, fileWatermark);
        } else if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
            // excel2pdf
            previewPath = etechFile.getPath().replace(".xlsx", ".pdf").replace(".xls", ".pdf");
            excel2pdf(getFileUploadDir(etechFile.getModule()) + etechFile.getPath(), getFilePreviewDir() + previewPath, fileWatermark);
        }
        if (StringUtil.isEmpty(previewPath) || !FileUtil.exist(getFilePreviewDir() + previewPath)) {
            // TODO error
            return null;
        }
        if (previewPath != null) {
            etechFile.setPreviewPath(previewPath);
            etechFileMapper.updateById(etechFile);
        }
        return previewPath;
    }

    /**
     * 模板文件转换
     */
    protected String makePreviewTemplateWithPath(String path, String fileName) throws Exception {
        log.debug("start makePreviewTemplateWithPath, path=" + path);
        fileName = fileName.toLowerCase();
        String fileType = FileUtil.getMimeType(fileName);
        String fileTempDir = getFileTempDir();
        String uid = IdUtil.getSuid();
        String previewPath = "";
        if (fileName.endsWith(".pdf")) {
            previewPath = path;
        } else if (fileName.endsWith(".doc") || fileName.endsWith(".docx")) {
            // word2pdf
            previewPath = fileTempDir + uid + "." + fileType;
            word2pdf(path, previewPath, null);
        } else if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
            // excel2pdf
            previewPath = fileTempDir + uid + "." + fileType;
            excel2pdf(path, previewPath, null);
        } else if (fileName.endsWith(".jpeg") || fileName.endsWith(".jpg")
                || fileName.endsWith(".gif") || fileName.endsWith(".png") ||
                fileName.endsWith(".bmp") || fileName.endsWith(".pic") ||
                fileName.endsWith(".tif") || fileName.endsWith(".tiff") || fileName.endsWith(".TIF")) {
            previewPath = path;
        }
        if (StringUtil.isEmpty(previewPath) || !FileUtil.exist(previewPath)) {
            throw new BusinessMessage("文件转预览文件失败");
        }
        return previewPath;
    }

    /**
     * 临时文件转换
     */
    protected String makePreviewTempWithPath(String path, String fileName, String fileWatermark) throws Exception {
        log.debug("start makePreviewWithPath, path=" + path);
        fileName = fileName.toLowerCase();
        String previewPath = "";
        if (fileName.endsWith(".pdf")) {
            previewPath = path;
            if (StringUtil.isNotEmpty(fileWatermark)) {
                pdfAddTextStamp(path, previewPath + "preview.pdf", fileWatermark, "file");
            }
        } else if (fileName.endsWith(".doc") || fileName.endsWith(".docx")) {
            // word2pdf
            previewPath = path.replace(".docx", ".pdf").replace(".doc", ".pdf");
            word2pdf(path, previewPath, fileWatermark);
        } else if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
            // excel2pdf
            previewPath = path.replace(".xlsx", ".pdf").replace(".xls", ".pdf");
            excel2pdf(path, previewPath, fileWatermark);
        } else if (fileName.endsWith(".jpeg") || fileName.endsWith(".jpg")
                || fileName.endsWith(".gif") || fileName.endsWith(".png") ||
                fileName.endsWith(".bmp") || fileName.endsWith(".pic") ||
                fileName.endsWith(".tif") || fileName.endsWith(".tiff")|| fileName.endsWith(".TIF")) {
            previewPath = path;
        }
        if (StringUtil.isEmpty(previewPath) || !FileUtil.exist(previewPath)) {
            throw new BusinessMessage("文件转预览文件失败");
        }
        return previewPath;
    }

    public static void word2pdf(String filePath, String previewPath, String watermark) throws Exception {
        com.aspose.words.Document doc = new com.aspose.words.Document(filePath);
        FileUtil.mkParentDirs(previewPath);
        doc.save(previewPath, SaveFormat.PDF);
        if (StringUtil.isNotEmpty(watermark)) {
            pdfAddTextStamp(previewPath, previewPath, watermark, "file");
        }
    }

    protected static void excel2pdf(String filePath, String previewPath, String watermark) throws Exception {
        boolean onePagePerSheet = false;
        try {
            HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            onePagePerSheet = RequestUtil.getBoolean(req, "onePagePerSheet", false);
        } catch (Exception e) {
        }
        excel2pdf(filePath, previewPath, watermark, onePagePerSheet);
    }

    /**
     * excel转pdf文件
     *
     * @param filePath
     * @param previewPath
     * @param watermark
     * @param onePagePerSheet 每张一页
     * @throws Exception
     */
    public static void excel2pdf(String filePath, String previewPath, String watermark, boolean onePagePerSheet) throws Exception {
        com.aspose.cells.Workbook book = new com.aspose.cells.Workbook(filePath);
        FileUtil.mkParentDirs(previewPath);
        PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
        pdfSaveOptions.setOnePagePerSheet(onePagePerSheet);
        book.save(previewPath, pdfSaveOptions);
        if (StringUtil.isNotEmpty(watermark)) {
            pdfAddTextStamp(previewPath, previewPath, watermark, "file");
        }
    }
//
//    public static void main(String[] args) {
//        pdfAddTextStamp("53.220.31-01.pdf", "53.220.31-01.wm.pdf", "工号：10221903 姓名：顾文涛\n存量", "lines");
//    }


    public static void pdfAddTextStamp(String srcPath, String destPath, String watermark, String model) {

        if (watermark.equals("document")){
            return;
        }
        PdfReader reader = null;
        PdfStamper stamper = null;
        final Logger logger = LoggerFactory.getLogger(EtechFileService.class);
        File f = null;
        try {
            reader = new PdfReader(new FileInputStream(srcPath));
            stamper = new PdfStamper(reader, new BufferedOutputStream(new FileOutputStream(new File(destPath))));
            PdfContentByte content;

            ClassPathResource classPathResource = new ClassPathResource("font/simhei.ttf");
            String tempPath = System.getProperty("java.io.tmpdir") + System.currentTimeMillis() + "simhei.ttf";
            f = new File(tempPath);
            IOUtils.copy(classPathResource.getInputStream(), new FileOutputStream(f));
            String fontPath = f.getAbsolutePath();


            BaseFont font = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

            PdfGState gs = new PdfGState();
            // 获取PDF页数
            int total = reader.getNumberOfPages();
            // 遍历每一页
            for (int i = 0; i < total; i++) {
                // 页宽度
                float width = reader.getPageSize(i + 1).getWidth();
                // 页高度
                float height = reader.getPageSize(i + 1).getHeight();

                int rot = reader.getPageRotation(i + 1);

                // 内容
                content = stamper.getOverContent(i + 1);
                //开始写入文本
                content.beginText();
                //水印透明度
                gs.setFillOpacity(0.9f);
                content.setGState(gs);
                content.setColorFill(BaseColor.LIGHT_GRAY);
                //设置字体的输出位置
                content.setTextMatrix(70, 200);

                if (model.equals("file")) {
                    float rotation = 30;
                    content.setFontAndSize(font, 20);

                    // 多行水印
                    int startIndex = 0;
                    int j = 0;
                    int endIndex = 0;
                    do {
                        endIndex = Math.min(startIndex + 17 + 8 * j, watermark.length());
                        String subString = watermark.substring(startIndex, endIndex);
                        content.showTextAligned(Element.ALIGN_LEFT, subString, 50 - 10 * j, height - (200 + 45 * j), rotation);
                        startIndex = endIndex;
                        j++;
                    } while (endIndex < watermark.length());


                    //平行居中的4条水印
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width / 2 - 100, height - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width / 2 - 100, height / 4 * 3 - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width / 2 - 100, height / 2 - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width / 2 - 100, height / 4 - 100, rotation);
                } else if (model.equals("user")) {

                    // 水印旋转度数
                    float rotation = 30;

                    // 左上角单条水印
                    content.setFontAndSize(font, 16);
                    content.showTextAligned(Element.ALIGN_LEFT, watermark, 50, height - 150, rotation);

                    // 左右两边个从上到下4条水印
//                    content.setFontAndSize(font, 16);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, 20, height - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, 20, height / 4 * 3 - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, 20, height / 2 - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, 20, height / 4 - 100, rotation);
//                    content.setFontAndSize(font, 16);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width/2 + 120, height - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width/2 + 120, height / 4 * 3 - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width/2 + 120, height / 2 - 100, rotation);
//                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width/2 + 120, height / 4 - 100, rotation);
                } else if (model.equals("lines")) {


                    float rotation = 30;
                    int ii = 0;
                    String[] texts = watermark.split("\n");
                    content.setFontAndSize(font, 20);


                    for (String text : texts) {
                        // 左上角单条水印

//                        if ((width > 1000 || height > 1000) && height > width) {
//                            float temp = width;
//                            width = height;
//                            height = temp;
//                        }


                        if (rot == 90){
                            log.info("Rotate >> {} Width >> {} Height >> {}", rot, height - 400 + ii * 20, height - (height * 67 / 100 + 45 * ii));
                            content.showTextAligned(Element.ALIGN_LEFT, text, height - 400 + ii * 20, height - (height * 67 / 100 + 45 * ii), rotation);
                        }else{
                            log.info("Rotate >> {} Width >> {} Height >> {}", rot, width - 400 + ii * 20,height - (height * 67 / 100 + 45 * ii));
                            content.showTextAligned(Element.ALIGN_LEFT, text, width - 400 + ii * 20, height - (height * 67 / 100 + 45 * ii), rotation);
                        }


                        ii++;
                    }


                } else if (model.equals("lines2")) {


                    float rotation = 30 ;
                    int ii = 0;
                    String[] texts = watermark.split("\n");
                    content.setFontAndSize(font, 20);


                    for (String text : texts) {
                        // 左上角单条水印

                        content.showTextAligned(Element.ALIGN_LEFT, text, 50, height - (200 + 45 * ii), rotation);
                        ii++;
                    }


                }

                //结束写入文本
                content.endText();
            }

            stamper.close();

        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessMessage(e.getLocalizedMessage());
        } catch (DocumentException e) {
            e.printStackTrace();
            throw new BusinessMessage(e.getLocalizedMessage());
        } finally {
            logger.debug("删除字体文件");
            try {
                FileUtil.del(f);
            } catch (Exception e) {
                logger.error("删除临时字体文件失败,{}", e);
            }

            if (stamper != null) {
                try {
                    stamper.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new BusinessMessage(e.getLocalizedMessage());
                } catch (DocumentException e) {
                    e.printStackTrace();
                    throw new BusinessMessage(e.getLocalizedMessage());
                }
            }
        }
    }

    public String getAbsUploadPath(String fileId) throws Exception {
        EtechFile etechFile = this.getFile(fileId);
        return getAbsUploadPath(etechFile);
    }

    public String getAbsUploadPath(EtechFile etechFile) throws Exception {
        if (etechFile == null) {
            return null;
        }
        return getFileUploadDir(etechFile.getModule()) + etechFile.getPath();
    }

    /**
     * 文件相关的的异常类英文转中文提示
     *
     * @param msg
     * @return
     */
    public String exceptionMsgToChiness(String msg) {
        if (StrUtil.isBlank(msg)) return msg;
        msg = msg.replace("File not exist", "文件不存在")
                .replace("java.io.FileNotFoundException", "找不到文件异常")
                .replace("No such file or directory", "无此文件或目录")
                .replace("Can't find file", "找不到文件");
        return msg;
    }

    /**
     * 验证文件是否存在
     *
     * @param fileId
     * @return
     */
    public boolean existById(String fileId) {
        if (StrUtil.isBlank(fileId)) {
            return false;
        }
        return existByFile(this.getFile(fileId));
    }

    /**
     * 验证文件是否存在
     *
     * @param etechFile
     * @return
     */
    public boolean existByFile(EtechFile etechFile) {
        if (etechFile == null) {
            return false;
        }
        return FileUtil.exist(getFileUploadDir(etechFile.getModule()) + etechFile.getPath());
    }

    private static File inputstream2file(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
            return file;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public ResultMsg zipFiles(String fileIds, HttpServletResponse response) {
        try {
            ArrayList<File> sourceFileList = new ArrayList<>();
            for (String id : fileIds.split(",")) {
                SysFile sysFile = etechFileMapper.selectById(id);

                this.logFileDownload4Zip(sysFile, "download", ContextUtil.getCurrentUserId());

                sourceFileList.add(inputstream2file(this.download(id), new File(sysFile.getName())));
            }

            String zipName = DateUtil.format(new DateTime(), "yyyyMMddHHmmss") + ".zip";
            File file = ZipUtil.zip(sourceFileList, new ZipFile(new File(zipName)));
            download(new FileInputStream(file), zipName, response);
            file.delete();// 删除临时zip文件
        } catch (Exception e) {
            e.printStackTrace();
            return ResultMsg.ERROR("打包下载失败:" + exceptionMsgToChiness(e.getLocalizedMessage()));
        }
        return null;
    }

    public void delete(String fileId, boolean removeFile) {
        EtechFile sysFile = getFile(fileId);
        if (sysFile == null) return;
        if (removeFile) {
            // remove file
            IUploader uploader = UploaderFactory.getUploader(sysFile.getUploader());
            uploader.remove(sysFile.getPath());
            // remove preview
            String previewPath = sysFile.getPreviewPath();
            if (StringUtil.isNotEmpty(previewPath)) {
                // 需要优化h获取物理路径
                //uploader.remove(previewPath);
            }

            etechFileMapper.deleteById(fileId);
        } else {
            //做逻辑删除
            sysFile.setDelete(true);
            etechFileMapper.updateById(sysFile);
        }
    }

    public void logFileDownload4Zip(SysFile sysFile, String action, String userId) {
        EtechFileLog fileLog = new EtechFileLog();
        fileLog.setId(IdUtil.getSuid());
        fileLog.setFileId(sysFile.getId());
        fileLog.setAction(action);
        fileLog.setUid(userId);
        fileLog.setPostdate(DateUtil.formatDateTime(new Date()));
        fileLog.setYear(DateUtil.year(new Date()));
        fileLogMapper.insert(fileLog);
        /*threadPoolTaskExecutor.execute(() -> {
            eltechFileJob.updateLogCount(sysFile.getId());
        });*/
    }

    public void logFilePreview(EtechFile etechFile, String content, String userId) {
        logFileAction(etechFile, "preview", content, userId);
    }

    public void logFileDownload(EtechFile etechFile, String content, String userId) {
        logFileAction(etechFile, "download", content, userId);
    }

    public void logFilePreviewDownload(EtechFile etechFile, String content, String userId) {
        logFileAction(etechFile, "previewDownload", content, userId);
    }

    private void logFileAction(EtechFile etechFile, String action, String content, String userId) {
        EtechFileLog fileLog = new EtechFileLog();
        fileLog.setId(IdUtil.getSuid());
        fileLog.setFileId(etechFile.getId());
        fileLog.setAction(action);
        fileLog.setUid(userId);
        fileLog.setPostdate(DateUtil.formatDateTime(new Date()));
        fileLog.setYear(DateUtil.year(new Date()));
        fileLogMapper.insert(fileLog);
        /*threadPoolTaskExecutor.execute(() -> {
            eltechFileJob.updateLogCount(etechFile.getId());
        });*/
    }

    public InputStream download(String fileId) {
        EtechFile sysFile = etechFileMapper.selectById(fileId);
        // TODO 需要检查是否兼容旧文件
        IUploader uploader = UploaderFactory.getUploader(sysFile.getUploader());
        return uploader.take(sysFile.getPath());
    }

    public EtechFile upload(InputStream is, String fileName, String module, String uniqueIdentifier) {
        try {
            return this.upload(is, fileName, null, module, uniqueIdentifier);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public EtechFile upload(InputStream is, String fileName) throws Exception {
        return this.upload(is, fileName, null);
    }

    public EtechFile upload(InputStream is, String fileName, String rightsJson) throws Exception {
        return this.upload(is, fileName, rightsJson, null, null);
    }

    /**
     * Etech定制Upload方法
     *
     * @param is
     * @param fileName
     * @param rightsJson
     * @return
     */
    public EtechFile upload(InputStream is, String fileName, String rightsJson, String module, String uniqueIdentifier) throws Exception {
        String ext = fileName.lastIndexOf('.') > -1 ? fileName.substring(fileName.lastIndexOf('.')) : "";
        String id = IdUtil.getSuid();

        // 1 先上传文件
        IUploader uploader = UploaderFactory.getDefault();
        String path = uploader.upload(is, id + ext);//以id为文件名保证不重复

        // 2 建立EtechFile数据
        EtechFile sysFile = new EtechFile();
        sysFile.setId(id);
        sysFile.setName(fileName);
        sysFile.setUploader(uploader.type());
        sysFile.setPath(path);
        sysFile.setModule(module);
        sysFile.setUniqueIdentifier(uniqueIdentifier);
        if(StrUtil.isBlank(uniqueIdentifier)){
            sysFile.setUniqueIdentifier(id);
        }
        if (StringUtil.isNotEmpty(rightsJson)) {
            sysFile.setRightsJson(rightsJson);
        }
        sysFile.setYear(DateUtil.year(new Date()));
        sysFile.setFileVersion("00");
        //3、查询版本号，版本号加一
        if (StringUtil.isNotEmpty(uniqueIdentifier)) {
            String sql = "select max(version_) version from sys_file where (delete_=0 or delete_ is null) and unique_identifier_=?";
            List<Map<String, Object>> list = DbUtil.getJdbcTemplate().queryForList(sql, uniqueIdentifier);
            if (list != null && list.size() > 0 && list.get(0).get("version") != null) {
                sysFile.setFileVersion(String.format("%02d", Integer.parseInt(list.get(0).get("version").toString()) + 1));
            }
        }
        sysFile.setLatest(1);
        sysFile.setFileType(FileUtil.getSuffix(fileName));
        sysFile.setFileMime(FileUtil.getMimeType(fileName));
        String fileAbsPath = getFileUploadDir(module) + path;
        sysFile.setFileLength(FileUtil.size(new File(fileAbsPath)));
        InputStream in = new FileInputStream(fileAbsPath);;
        sysFile.setMd5(DigestUtils.md5Hex(new FileInputStream(fileAbsPath)));
        IoUtil.closeIfPosible(in);
        // 4 保存
        etechFileMapper.insert(sysFile);
        //5、修改历史版本 最新版本标志
        if (sysFile.getFileVersion() != null && !"00".equals(sysFile.getFileVersion())) {
            EtechFile f = new EtechFile();
            f.setLatest(0);
            etechFileMapper.update(f, new UpdateWrapper<EtechFile>().lambda()
                    .eq(EtechFile::getUniqueIdentifier, uniqueIdentifier));
        }
        //6、创建生成预览文件的任务
        //etechFileTaskService.createTask(sysFile.getId(), ext);
        return sysFile;
    }

    /**
     * 获取日志
     *
     * @param file
     */
    public void setLogsByFile(EtechFile file) {
        if (file != null && StrUtil.isNotBlank(file.getId())) {
            file.setLogList(fileLogMapper.getByFileId(file.getId()));
        }
    }

    /**
     * 获取版本列表
     *
     * @param file
     */
    public void setVersionsByFile(EtechFile file) {
        if (file != null && StrUtil.isNotBlank(file.getUniqueIdentifier())) {
            List<EtechFileVersionVo> versionVos = etechFileMapper.selectFileVersionsByFileId(file.getUniqueIdentifier());
            for (EtechFileVersionVo versionVo : versionVos) {
                if (StrUtil.isBlank(versionVo.getFileType())) {
                    versionVo.setFileType(FileUtil.extName(versionVo.getName()));
                }
            }
            file.setVersionList(versionVos);
        }
    }

    public EtechFile getFile(String fileId) {
        return etechFileMapper.selectById(fileId);
    }

    /**
     * 获取预览的文件详情
     *
     * @param fileId
     * @return
     */
    public EtechFile getFilePreviewDetail(String fileId) {
        EtechFile file = etechFileMapper.selectById(fileId);
        if (file == null) {//查询不到查询临时表
            file = new EtechFile();
            EtechFileTemp etechFileTemp = etechFileTempMapper.selectById(fileId);
            BeanUtil.copyProperties(etechFileTemp, file);
        }
        if (file != null) {
            // 检查读取权限（预览下载）
            /*if (!file.havePreviewRights()) {
                // TODO 检查权限
                ResultMsg.ERROR("无读取文件权限");
            }*/
            IUser user = userService.getUserById(file.getCreateBy());
            if (user != null) {
                file.setCreateByName(user.getFullname());
            }
            setLogsByFile(file);
            setVersionsByFile(file);
            boolean withWatermark = false;
            //图纸和工艺模块的加水印
            if (StrUtil.isNotBlank(file.getModule()) && CollUtil.newArrayList("drawing", "process").indexOf(file.getModule()) > -1) {
                withWatermark = true;
            }
            file.setPreviewUrl(getPreviewUrl(file, withWatermark));
        }
        return file;
    }

    /**
     * 获取预览文件的url
     *
     * @param file
     * @param withWatermark 是否带水印
     * @return
     */
    public String getPreviewUrl(EtechFile file, boolean withWatermark) {
        String paramsStr = "fileId=" + file.getId() + "&uid=" + ContextUtil.getCurrentUserId();
        if (withWatermark) {
            //默认用户水印
            String watermarkTxt = "工号：" + ContextUtil.getCurrentUserAccount() + " 日期：" + DateUtil.formatDate(new Date());
            paramsStr = paramsStr + "&watermarkTxt=" + URLUtil.encode(watermarkTxt);
        }
        //MD5签名
        String md5 = SecureUtil.md5(paramsStr + "&date=" + DateUtil.format(new Date(), "yyyyMMdd") + "&password=" + urlEncryptionPassword);
        String base64String = Base64.encodeBase64String(URLUtil.encode(paramsStr, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8));
        String previewUrl = getOnlinePreviewHost() + "onlinePreviewEtech?fileUrl=" + base64String + "&sign=" + md5;
        return previewUrl;
    }

    /**
     * 处理文件预览 队列生成
     *
     * @param fileId
     */
    public void generationOfPreviewFiles(String fileId) {
        generationOfPreviewFiles(fileId, null, false);
    }

    /**
     * 处理文件预览 队列生成
     *
     * @param fileId
     */
    public boolean generationOfPreviewFiles(String fileId, Long filelistId) {
        return generationOfPreviewFiles(fileId, filelistId, false);
    }

    //重新生成预览文件
    public boolean rePreview(String fileId, String busType) {
        Long fileListId = null;
        if (StringUtil.isEmpty(busType) || "drawing".equals(busType)) {
            String sql = "select filelistid,businessid from file_drawing where uploadseries=?";
            List<Map<String, Object>> list = DbUtil.getJdbcTemplate().queryForList(sql, fileId);
            fileListId = (list != null && list.size() > 0 && list.get(0).get("filelistid") != null) ? (Long) list.get(0).get("filelistid") : null;
        }
        DbUtil.getJdbcTemplate().update("update sys_file set preview_=null where id_=?", fileId);
        return generationOfPreviewFiles(fileId, fileListId, false);
    }

    /**
     * 处理文件预览
     *
     * @param fileId
     * @param real   是否实时生成预览文件
     */
    public boolean generationOfPreviewFiles(String fileId, Long filelistId, boolean real) {
        long start = System.currentTimeMillis();
        //先发送到待转换队列，加快前端第一次请求的速度
       /* String url = "addTask?fileId=" + fileId;
        //如果是http开头的
        if (getOnlinePreviewHost().startsWith("http")) {
            url = getOnlinePreviewHost() + url;
        } else {
            //不是http开头的说明是走的nginx配置
            HttpServletRequest request = RequestHolder.getRequest();

            log.info("X-Forwarded-For:{}", request.getHeader("X-Forwarded-For"));
            log.info("X-Forwarded-Proto:{}", request.getHeader("X-Forwarded-Proto"));
            log.info("Host:{}", request.getHeader("Host"));
            log.info("X-Forwarded-Host:{}", request.getHeader("X-Forwarded-Host"));
            log.info("X-Forwarded-Port:{}", request.getHeader("X-Forwarded-Port"));
            log.info("X-Real-IP:{}", request.getHeader("X-Real-IP"));

            String host = request.getHeader("Host");
            if (StrUtil.isNotBlank(host)) {
                //文件服务器端口 docker中是80替换为8012
                host = host.replace(":80", ":8012");
                log.info("前端请求地址:{}", host);
                url = "http://" + host + getOnlinePreviewHost() + url;
            } else {
                //取后台配置的前端地址
                url = RequestHolder.getUrl() + getOnlinePreviewHost() + url;
            }
        }*/
//        String url = "http://fileview:8080/fileview/addTask?fileId=" + fileId;
        String url = "http://" + RequestHolder.getRequest().getHeader("Host") + "/fileview/addTask?fileId=" + fileId;
        try {
            //本地启动的如果配置的是nginx这里不发送预处理请求
            if (real) {
                url += "&real=1";
            }
            if (filelistId != null && filelistId > 0) {
                url += "&filelistId=" + filelistId;
            }
            log.info("发送生成预览url:" + url);
            String result = HttpUtil.get(url);
            log.info("发送生成预览result:" + result);
            return "success".equals(result);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("发送生成预览文件队列失败，url:" + url);
            return false;
        } finally {
            log.info("generationOfPreviewFiles生成预览文件耗时：{}ms.", System.currentTimeMillis() - start);
        }
    }

    /**
     * 获取预览的临时文件详情
     *
     * //@param path
     * //@param withWatermark 是否带水印
     * @return
     */
    /*public JSONObject getTempFilePreviewDetail(String path, String fileId, boolean withWatermark) throws MalformedURLException {
        String filePath = null;
        String module = "etech";
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("hasPreviewRight4currentUser", true);
        jsonObject.set("hasPreviewDRight4currentUser", true);
        jsonObject.set("hasDownloadRight4currentUser", true);
        jsonObject.set("logList", CollUtil.newArrayList());
        if (StringUtil.isNotEmpty(fileId)) {
            EtechFileTemp temp = etechFileTempMapper.selectById(fileId);
            if (temp != null) {
                filePath = StringUtil.isNotEmpty(temp.getPreviewPath()) ? temp.getPreviewPath() : temp.getPath();
                module = temp.getModule();
                jsonObject.set("hasPreviewRight4currentUser", temp.isHasPreviewRight4currentUser());
                jsonObject.set("hasPreviewDRight4currentUser", temp.isHasPreviewDRight4currentUser());
                jsonObject.set("hasDownloadRight4currentUser", temp.isHasDownloadRight4currentUser());
            }
        }
        if (StringUtil.isNotEmpty(path) && StringUtil.isEmpty(filePath)) {

            String[] sss = path.split("\\.");
            List<String> num = new ArrayList<>();
            for (int i = 0; i < sss.length-1; i++){
                num.add(sss[i]);
            }

            String docnum = String.join(".", num);
            log.info("TEMP 反查资料 {}", docnum);
            List<ProjDoc> docs = docMapper.selectList(new QueryWrapper<ProjDoc>().lambda().eq(ProjDoc::getDocnum, docnum));
            if (docs != null && docs.size() > 0){
                ProjDoc doc = docs.get(0);

                String fileid = doc.getContentAtt();
                EtechFile file = getFilePreviewDetail(fileid);

                jsonObject.set("hasDownloadRight4currentUser", file.isHasDownloadRight4currentUser());
                jsonObject.set("hasPreviewRight4currentUser", file.isHasPreviewRight4currentUser());
                jsonObject.set("hasPreviewDRight4currentUser", file.isHasPreviewDRight4currentUser());

                jsonObject.set("download", file.getDownload());
                jsonObject.set("online", file.getOnline());
                jsonObject.set("logList", file.getLogList());
            }



            filePath = URLUtil.decode(path);
            filePath = filePath.replaceAll("\\\\", "/");
            if (filePath.split("/").length == 5) {//5段是带模块路径
                module = filePath.split("/")[0];
            }
        }
        String tempDir = this.getFileTempDir();
        if (!FileUtil.exist(tempDir + filePath)) {
            throw new BusinessMessage("文件不存在无法预览");
        }
        jsonObject.set("name", FileUtil.getName(filePath));
        jsonObject.set("module", module);

        jsonObject.set("versionList", CollUtil.newArrayList());
        String paramsStr = "path=" + filePath.replace("\\", "/");
        paramsStr += "&uid=" + ContextUtil.getCurrentUserId();
        if (withWatermark) {
            //默认用户水印
            String watermarkTxt = "工号：" + ContextUtil.getCurrentUserAccount() + " 日期：" + DateUtil.formatDate(new Date());
            paramsStr = paramsStr + "&watermarkTxt=" + watermarkTxt;
        }
//        boolean isProd = PropertyUtil.getPropertyService().getByAlias("systemEnvironmentVariables").equals("prod");
//        if (isProd) {
//            previewUrl += "&baseUrl=" + URLUtil.encode("http://etech.stcetech.ad01.sec.com") + baseUrl;
//        } else {
//            previewUrl += "&baseUrl=" + URLUtil.encode("http://192.168.8.106:6111") + baseUrl;
//        }
        String base64String = Base64.encodeBase64String(URLUtil.encode(paramsStr, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8));
        //MD5签名
        String md5 = SecureUtil.md5(paramsStr + "&date=" + DateUtil.format(new Date(), "yyyyMMdd") + "&password=" + urlEncryptionPassword);
        String previewUrl = getOnlinePreviewHost() + "onlinePreviewTemp?path=" + base64String + "&sign=" + md5;
        jsonObject.set("previewUrl", previewUrl);
        return jsonObject;
    }*/

    public String uploadTemp(MultipartFile file) throws Exception {
        String fileFullName = IdUtil.getSuid() + ".pdf";
        String fileFullPath = getFileTempDir() + fileFullName;
        FileUtil.writeFromStream(file.getInputStream(), fileFullPath);

        return fileFullName;
    }

    // 直接对上传文件打网格
    public String addGrid(MultipartFile file) throws Exception {
        String originalFileFullName = file.getOriginalFilename();
        if (!"pdf".equalsIgnoreCase(FileUtil.getSuffix(originalFileFullName))) {
            throw new RuntimeException("当前仅支持对 pdf 文件！");
        }

        String fileTempDir = getFileTempDir();

        String tempPath = fileTempDir + IdUtil.getSuid() + ".pdf";
        String griddedPath = fileTempDir + "gridded-" + originalFileFullName;

        FileUtil.writeFromStream(file.getInputStream(), tempPath);
        addGrid(tempPath, griddedPath);

        return griddedPath;

    }

    // 对服务器 temp文件夹中指定文件打网格
    // srcPath 文件全路径，比如 /xxx/test.pdf
    public String addGridInTemp(String fileFullName, String newFileFullName) throws Exception {
        String srcPath = getFileTempDir() + fileFullName;
        String destPath = getDestTempPath(fileFullName, newFileFullName);
        addGrid(srcPath, destPath);

        return destPath;
    }

    public void addGrid(String srcPath, String destPath) throws Exception {

        PdfReader reader = null;
        PdfStamper stamper = null;
        File fontFile = null;

        try {
            reader = new PdfReader(srcPath, "PDF".getBytes());
            stamper = new PdfStamper(reader, new BufferedOutputStream(new FileOutputStream(new File(destPath))));
            PdfContentByte content;

            ClassPathResource classPathResource = new ClassPathResource("font/simhei.ttf");
            String tempPath = System.getProperty("java.io.tmpdir") + System.currentTimeMillis() + "simhei.ttf";
            fontFile = new File(tempPath);
            IOUtils.copy(classPathResource.getInputStream(), new FileOutputStream(fontFile));
            String fontPath = fontFile.getAbsolutePath();
            BaseFont font = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.3f);

            Image horizontal = Image.getInstance(staticPath + "signature/horizontal.png");
            Image vertical = Image.getInstance(staticPath + "signature/vertical.png");

            int pageSize = reader.getNumberOfPages();
            for (int i = 1; i <= pageSize; i++) {
                for (int j = 1; j < 20; j++) {
                    int offset = 50 * j;

                    content = stamper.getOverContent(i);
                    content.setGState(gs);

                    content.beginText();
                    content.setFontAndSize(font, 20);
                    content.showTextAligned(Element.ALIGN_LEFT, String.valueOf(offset), 0, offset, 0);
                    content.showTextAligned(Element.ALIGN_LEFT, String.valueOf(offset), offset, 0, 0);
                    content.endText();

                    horizontal.setAbsolutePosition(0, offset);
                    vertical.setAbsolutePosition(offset, 0);
                    content.addImage(horizontal);
                    content.addImage(vertical);
                }
            }

            stamper.close();
            reader.close();

        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessMessage(e.getLocalizedMessage());
        } catch (DocumentException e) {
            e.printStackTrace();
            throw new BusinessMessage(e.getLocalizedMessage());
        } finally {
            LOGGER.debug("删除字体文件");
            try {
                FileUtil.del(fontFile);
            } catch (Exception e) {
                LOGGER.error("删除临时字体文件失败,{}", e);
            }

            if (stamper != null) {
                try {
                    stamper.close();
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new BusinessMessage(e.getLocalizedMessage());
                } catch (DocumentException e) {
                    e.printStackTrace();
                    throw new BusinessMessage(e.getLocalizedMessage());
                }
            }
        }

    }


    public void checkSignature(String uid) {
        String path = staticPath + "signature/" + uid + ".png";
        checkSignature(path, uid);
    }

    public void checkSignature(String path, String uid) {
        if (!FileUtil.exist(path)) {
            String account = EtechUserUtil.getUserAccountById(uid);
            String name = EtechUserUtil.getUserNameById(uid);

            throw new RuntimeException("用户 [ " + account + " " + name + " ] 的签名文件不存在！ ");
        }

    }

    public String addSignature(com.alibaba.fastjson.JSONObject req) throws Exception {
        if (req == null) {
            throw new RuntimeException("参数为空！");
        }

        String fileFullName = req.getString("fileFullName");
        String newFileFullName = req.getString("newFileFullName");
        List<SignatureDto> signatureList = com.alibaba.fastjson.JSONObject.parseArray(req.getString("signatureList"), SignatureDto.class);

        String srcPath = getFileTempDir() + fileFullName;
        String destPath = getDestTempPath(fileFullName, newFileFullName);

        return addSignature(srcPath, destPath, signatureList);


    }


    public String addSignature(String srcPath, String destPath, List<SignatureDto> signatureList) throws Exception {
        return addSignature(srcPath, destPath, signatureList, 100, 33);
    }

    /**
     * @param srcPath       要打签名的文件路径
     * @param destPath      打好签名的文件保存路径
     * @param signatureList 签名数据
     * @return
     * @throws Exception
     */
    public String addSignature(String srcPath, String destPath, List<SignatureDto> signatureList, float newWidth, float newHeight) throws Exception {

        PdfReader reader = null;
        PdfStamper stamper = null;

        try {
            reader = new PdfReader(srcPath, "PDF".getBytes());
            stamper = new PdfStamper(reader, new BufferedOutputStream(new FileOutputStream(new File(destPath))));
            PdfContentByte content;

            PdfGState gs = new PdfGState();

            for (SignatureDto signatureDto : signatureList) {
                content = stamper.getOverContent(signatureDto.getPage());
                content.setGState(gs);

                for (PositionDto positionDto : signatureDto.getPositionList()) {
                    String signaturePath = staticPath + "signature/" + positionDto.getUid() + ".png";
                    checkSignature(signaturePath, positionDto.getUid().toString());

                    Image signature = Image.getInstance(signaturePath);
                    signature.scaleAbsolute(newWidth, newHeight);
                    signature.setAbsolutePosition(
                            positionDto.getX(),
                            positionDto.getY() - 20
                    );

                    content.addImage(signature);
                }

            }

            stamper.close();
            reader.close();

            return destPath;

        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessMessage(e.getLocalizedMessage());
        } catch (DocumentException e) {
            e.printStackTrace();
            throw new BusinessMessage(e.getLocalizedMessage());
        } finally {
            if (stamper != null) {
                try {
                    stamper.close();
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new BusinessMessage(e.getLocalizedMessage());
                } catch (DocumentException e) {
                    e.printStackTrace();
                    throw new BusinessMessage(e.getLocalizedMessage());
                }
            }
        }

    }

    // srcPath 文件全路径，比如 /xxx/test.pdf
    private String getDestTempPath(String fileFullName, String newFileFullName) throws Exception {
        String srcPath = getFileTempDir() + fileFullName;

        if (!"pdf".equalsIgnoreCase(FileUtil.getSuffix(srcPath))) {
            throw new RuntimeException("当前仅支持对 pdf 文件！");
        }

        if (!FileUtil.exist(srcPath)) {
            throw new RuntimeException("文件不存在 path=[" + srcPath + "]");
        }


        String fileTempDir = getFileTempDir();
        String destPath = fileTempDir + newFileFullName;

        return destPath;

    }


}
